package cn.wolfcode.business.service.impl;

import java.io.InputStream;
import java.util.*;

import cn.wolfcode.business.domain.BusBpmnInfo;
import cn.wolfcode.business.domain.BusServiceItem;
import cn.wolfcode.business.domain.vo.CarPackageAuditVo;
import cn.wolfcode.business.domain.vo.HistoryVo;
import cn.wolfcode.business.service.IBusBpmnInfoService;
import cn.wolfcode.business.service.IBusServiceItemService;
import cn.wolfcode.business.util.DateUtil;
import cn.wolfcode.common.core.domain.model.LoginUser;
import cn.wolfcode.common.utils.DateUtils;
import cn.wolfcode.common.utils.PageUtils;
import cn.wolfcode.common.utils.SecurityUtils;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Comment;
import org.activiti.engine.task.Task;
import org.activiti.engine.task.TaskInfo;
import org.activiti.image.impl.DefaultProcessDiagramGenerator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import cn.wolfcode.business.mapper.BusCarPackageAuditMapper;
import cn.wolfcode.business.domain.BusCarPackageAudit;
import cn.wolfcode.business.service.IBusCarPackageAuditService;
import org.springframework.transaction.annotation.Transactional;

/**
 * 套餐审核Service业务层处理
 *
 * @author lyh
 * @date 2025-09-25
 */
@Service
public class BusCarPackageAuditServiceImpl implements IBusCarPackageAuditService {
    @Autowired
    private BusCarPackageAuditMapper busCarPackageAuditMapper;
    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    private RuntimeService runtimeService;
    @Autowired
    private IBusServiceItemService serviceItemService;
    @Autowired
    private HistoryService historyService;
    @Autowired
    private TaskService taskService;
    @Autowired
    private IBusBpmnInfoService busBpmnInfoService;

    /**
     * 查询套餐审核
     *
     * @param id 套餐审核主键
     * @return 套餐审核
     */
    @Override
    public BusCarPackageAudit selectBusCarPackageAuditById(Long id) {
        return busCarPackageAuditMapper.selectBusCarPackageAuditById(id);
    }

    /**
     * 查询套餐审核列表
     *
     * @param busCarPackageAudit 套餐审核
     * @return 套餐审核
     */
    @Override
    public List<BusCarPackageAudit> selectBusCarPackageAuditList(BusCarPackageAudit busCarPackageAudit) {

        String endCreateTime = (String) busCarPackageAudit.getParams().get("endCreatTime");

// 将结束创建时间字符串转换为日期对象
        Date date = DateUtil.parseDate(endCreateTime, "yyyy-MM-dd");

// 调整日期范围：将日期加1天，再减1秒，得到当天的最后一秒
        Date modifyDate = DateUtil.changeDate(date, Calendar.DAY_OF_YEAR, 1);
        Date changedDate = DateUtil.changeDate(modifyDate, Calendar.SECOND, -1);

// 将调整后的日期转换为指定格式的字符串
        String time = DateUtil.Date2String(changedDate, "yyyy-MM-dd HH:mm:ss");

// 更新查询参数中的结束创建时间
        busCarPackageAudit.getParams().put("endCreatTime", time);

        return busCarPackageAuditMapper.selectBusCarPackageAuditList(busCarPackageAudit);

    }

    /**
     * 新增套餐审核
     *
     * @param busCarPackageAudit 套餐审核
     * @return 结果
     */
    @Override
    public int insertBusCarPackageAudit(BusCarPackageAudit busCarPackageAudit) {
        busCarPackageAudit.setCreateTime(DateUtils.getNowDate());
        return busCarPackageAuditMapper.insertBusCarPackageAudit(busCarPackageAudit);
    }

    /**
     * 修改套餐审核
     *
     * @param busCarPackageAudit 套餐审核
     * @return 结果
     */
    @Override
    public int updateBusCarPackageAudit(BusCarPackageAudit busCarPackageAudit) {
        return busCarPackageAuditMapper.updateBusCarPackageAudit(busCarPackageAudit);
    }

    /**
     * 批量删除套餐审核
     *
     * @param ids 需要删除的套餐审核主键
     * @return 结果
     */
    @Override
    public int deleteBusCarPackageAuditByIds(Long[] ids) {
        return busCarPackageAuditMapper.deleteBusCarPackageAuditByIds(ids);
    }

    /**
     * 删除套餐审核信息
     *
     * @param id 套餐审核主键
     * @return 结果
     */
    @Override
    public int deleteBusCarPackageAuditById(Long id) {
        return busCarPackageAuditMapper.deleteBusCarPackageAuditById(id);
    }

    @Override
    public InputStream showProcessImg(Long instanceId) {
        // 参数合理化验证
        if(instanceId == null){
            throw new RuntimeException("非法参数");
        }
        // 定义插件对象
        DefaultProcessDiagramGenerator processDiagramGenerator = new DefaultProcessDiagramGenerator();
        // 根据传递的 instanceId 流程实例 id 查询流程定义对象
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
                .processInstanceId(instanceId.toString())
                .singleResult();
        BpmnModel bpmnModel = null;
        List<String> activeActivityIds = new ArrayList<>();
        if(processInstance == null){
            // 流程被撤销了  我们就查询历史流程实例
            HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
                    .processInstanceId(instanceId.toString())
                    .singleResult();
            bpmnModel = repositoryService.getBpmnModel(historicProcessInstance.getProcessDefinitionId());
            // 我们就不用传递任何活动节点了。因为已经是历史了。
        } else {
            // 获取 BpmnModel 对象
            bpmnModel = repositoryService.getBpmnModel(processInstance.getProcessDefinitionId());
            // 获取当前活动的节点
            activeActivityIds = runtimeService.getActiveActivityIds(instanceId.toString());
        }

        // 使用插件生成流程图
        InputStream inputStream = processDiagramGenerator.generateDiagram(
                bpmnModel,
                activeActivityIds,            // 活动的节点集合
                Collections.emptyList(),            // 活动的连线集合
                "宋体",
                "宋体",
                "宋体"
        );
        return inputStream;
    }

    /**
     * 流程撤销
     * @param id 流程审核表 id
     * @return  结果
     */
    @Override
    @Transactional
    public int processCancel(Long id) {
        // 参数合理化验证
        if(id == null){
            throw new RuntimeException("非法参数");
        }
        // 根据传入的 id 查询 流程审核 对象
        BusCarPackageAudit audit = this.selectBusCarPackageAuditById(id);
        if(audit == null){
            throw new RuntimeException("非法参数");
        }
        // 验证状态，必须是审核中的才可以进行撤销操作。
        if(!BusCarPackageAudit.STATUS_IN_PROGRESS.equals(audit.getStatus())){
            throw new RuntimeException("只有审核中的流程才可以进行撤销操作");
        }
        // 修改当前流程审核表状态 --> 流程撤销
        busCarPackageAuditMapper.changeAuditStatus(id,BusCarPackageAudit.STATUS_CANCEL);
        // 删除流程实例
        runtimeService.deleteProcessInstance(audit.getInstanceId(),"撤销流程");
        // 修改服务项状态 --> 初始化
        return serviceItemService.changeAuditStatus(audit.getServiceItemId(), BusServiceItem.AUDITSTATUS_INIT);
    }

    /**
     * 查看历史审批信息列表
     * @param instanceId 流程实例 id
     * @return 历史审批信息列表
     */
    @Override
    public List<HistoryVo> getHistoryTaskList(Long instanceId) {
        // 参数合理化验证
        if (instanceId == null) {
            throw new RuntimeException("非法参数");
        }
        // 根据传入的流程实例 id 查询历史任务
        List<HistoricTaskInstance> historicTaskList = historyService.createHistoricTaskInstanceQuery()
                .processInstanceId(instanceId.toString())
                .list();
        // 使用 jdk8 新特性遍历这些历任事务集合，封装到每一个 Vo 对象中，最终再将每个 Vo 对象封装到集合中。
        List<HistoryVo> historyVoList = historicTaskList.stream().map(task -> {
            HistoryVo vo = new HistoryVo();
            vo.setTaskName(task.getName());
            vo.setStartTime(DateUtil.Date2String(task.getStartTime(), "yyyy-MM-dd HH:mm:ss"));
            // 有可能当前任务并没有审批结束，所以不一定存在结束时间和总耗时。
            if (task.getEndTime() != null && task.getDurationInMillis() != null) {
                vo.setEndTime(DateUtil.Date2String(task.getEndTime(), "yyyy-MM-dd HH:mm:ss"));
                vo.setDurationInMillis(task.getDurationInMillis() / 1000 + "s");
            }
            // 查询历史任务的审批信息，存在才进行封装
            List<Comment> taskComments = taskService.getTaskComments(task.getId());
            if (taskComments != null && !taskComments.isEmpty()) {
                for (Comment taskComment : taskComments) {
                    vo.setComment(taskComment.getFullMessage());
                }
            }
            return vo;
        }).toList();    // jdk 17直接使用 toList()， jdk8 写法  collect(Collectors.toList());
        return historyVoList;
    }

    @Override
    public List<BusCarPackageAudit> todoTaskList(BusCarPackageAudit busCarPackageAudit) {
        // 获取当前登录用户（审批人）
        Long userId = SecurityUtils.getUserId();
        // 获取流程定义的 Key  --> 到 BpmnInfo 对象中获取  --> 获取 BpmnInfo 对象。（流程定义 Key）
        BusBpmnInfo bpmnInfo = busBpmnInfoService.selectBusBpmnInfoByType(BusCarPackageAudit.FLOW_AUDIT_TYPE);
        String processDefinitionKey = bpmnInfo.getProcessDefinitionKey();
        // 根据 流程定义的 Key 和 审批人查询到我们的代办任务列表
        List<Task> taskList = taskService.createTaskQuery()
                .processDefinitionKey(processDefinitionKey)
                .taskAssignee(userId.toString())
                .list();
        // 若没查询到任务我们应该返回一个空集合。
        if(taskList == null || taskList.isEmpty()){
            return Collections.emptyList();
        }
        // 遍历任务集合，拿到每个任务对应的流程实例 id，将这些获取到的流程实例 id 封装为集合。
        // Stream流写法
        // List<String> list = taskList.stream().map(task -> {
        //     return task.getProcessInstanceId();
        // }).toList();
        // 方法的引用写法  相当于每次遍历都调用我们对应任务类 TaskInfo 中的 getProcessInstanceId 方法。本质还是获取每个任务对应的 id
        List<String> processInstanceIdList = taskList.stream().map(TaskInfo::getProcessInstanceId).toList();

        // 向额外参数中添加 processInstanceIdList ，这样就会传输到 XML 中
        // (根据这些流程实例集合去数据库中查询），该查询结果需要分页
        PageUtils.startPage();  // 在这里才可以进行分页操作
        if(processInstanceIdList != null && !processInstanceIdList.isEmpty()){
            busCarPackageAudit.getParams().put("processInstanceIdList",processInstanceIdList);
        }
        return busCarPackageAuditMapper.selectBusCarPackageAuditList(busCarPackageAudit);
    }

    @Override
    public int audit(CarPackageAuditVo vo) {
        // 参数合理化验证
        if(vo == null || vo.getId() == null || vo.getAuditStatus() == null){
            throw new RuntimeException("非法参数");
        }
        // 根据传入的套餐记录 id 查询 套餐列表对象
        BusCarPackageAudit busCarPackageAudit = this.selectBusCarPackageAuditById(vo.getId());
        if(busCarPackageAudit == null){
            throw new RuntimeException("非法参数");
        }
        // 状态是审批中才可以进行审批操作
        if(!BusCarPackageAudit.STATUS_IN_PROGRESS.equals(busCarPackageAudit.getStatus())){
            throw new RuntimeException("任务必须处于审批中才可以进行审批操作");
        }
        // 从 busCarPackageAudit 对象中获取流程实例 id
        String instanceId = busCarPackageAudit.getInstanceId();
        // 获取任务负责人（当前登录用户）
        String userId = SecurityUtils.getUserId().toString();
        // 根据流程实例 id 和 任务负责人查询指定 待办任务。
        Task task = taskService.createTaskQuery()
                .processInstanceId(instanceId)
                .taskAssignee(userId)
                .singleResult();
        if(task == null){
            throw new RuntimeException("非法参数");
        }
        // 添加批注信息   审批人xxx同意-审批意见[xxxx]；
        StringBuilder msg = new StringBuilder("审批人：");
        msg.append(((LoginUser)SecurityUtils.getAuthentication().getPrincipal()).getUser().getNickName());
        boolean auditStatus = BusCarPackageAudit.STATUS_PASS.equals(vo.getAuditStatus());
        if(auditStatus){
            // 审批人选择了通过
            msg.append("同意-审批意见[");
        } else {
            // 审批人选择了未通过
            msg.append("拒绝-审批意见[");
        }
        msg.append(vo.getAuditInfo()).append("]");
        taskService.addComment(task.getId(),instanceId,msg.toString());
        // 设置流程变量 shopOwner 来控制流程 同意还是拒绝
        Map<String,Object> params = new HashMap<>();
        params.put("shopOwner",auditStatus);
        // 若审批人选择同意，则添加折扣价格，来决定是否 >= 3000？ 是否需要财务审批。
        if(auditStatus){
            // Activiti7 中的流程变量是不支持 BigDecimal 类型的。所以我们必须转换为 Long||Double。
            params.put("disCountPrice",busCarPackageAudit.getServiceItemPrice().doubleValue());
        }
        // 完成任务
        taskService.complete(task.getId(),params);
        int count = 0;
        // 判断审批人具体选择的是同意还是拒绝
        if(auditStatus){
            // 审批通过
            // 我们需要查看是否还有下一个任务 （再次查询任务）
            List<Task> nextTaskList = taskService.createTaskQuery()
                    .processInstanceId(instanceId)
                    .list();
            if(nextTaskList == null || nextTaskList.isEmpty()){
                // 说明没有下一个任务了。
                // 审批通过
                // 修改 套餐列表 状态 --> 审核通过
                busCarPackageAuditMapper.changeAuditStatus(busCarPackageAudit.getId(),BusCarPackageAudit.STATUS_PASS);
                // 修改其对应的服务项状态 --> 审核通过
                count = serviceItemService.changeAuditStatus(busCarPackageAudit.getServiceItemId(),BusServiceItem.AUDITSTATUS_APPROVED);
            } else {
                count = 1;
            }
        } else {
            // 审批拒绝
            // 修改 套餐列表 状态 --> 审核拒绝
            busCarPackageAuditMapper.changeAuditStatus(busCarPackageAudit.getId(),BusCarPackageAudit.STATUS_REJECT);
            // 修改其对应的服务项状态 --> 审核拒绝
            return serviceItemService.changeAuditStatus(busCarPackageAudit.getServiceItemId(),BusServiceItem.AUDITSTATUS_REPLY);
        }
        return count;
    }

    @Override
    public List<BusCarPackageAudit> doneTaskList(BusCarPackageAudit busCarPackageAudit) {
        // 获取当前登录用户（审批人）
        Long userId = SecurityUtils.getUserId();
        // 获取流程定义的 Key  --> 到 BpmnInfo 对象中获取  --> 获取 BpmnInfo 对象。（流程定义 Key）
        BusBpmnInfo bpmnInfo = busBpmnInfoService.selectBusBpmnInfoByType(BusCarPackageAudit.FLOW_AUDIT_TYPE);
        String processDefinitionKey = bpmnInfo.getProcessDefinitionKey();
        // 根据 流程定义的 Key 和 审批人查询到我们的代办任务列表
        List<HistoricTaskInstance> historyList = historyService.createHistoricTaskInstanceQuery()
                .processDefinitionKey(processDefinitionKey)
                .taskAssignee(userId.toString())
                .finished()     // 已完成任务
                .list();
        // 若没查询到任务我们应该返回一个空集合。
        if(historyList == null || historyList.isEmpty()){
            return Collections.emptyList();
        }
        List<String> processInstanceIdList = historyList.stream().map(TaskInfo::getProcessInstanceId).toList();

        PageUtils.startPage();  // 在这里才可以进行分页操作
        if(processInstanceIdList != null && !processInstanceIdList.isEmpty()){
            busCarPackageAudit.getParams().put("processInstanceIdList",processInstanceIdList);
        }
        return busCarPackageAuditMapper.selectBusCarPackageAuditList(busCarPackageAudit);
    }
}
